package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.*;
import com.sc.nft.entity.vo.*;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.sc.nft.enums.task.TaskPrizeTypeEnum.INTEGRAL;
import static com.sc.nft.sup.ErrorCode.CHECK_HOLD_COLLECTION;
import static com.sc.nft.sup.ErrorCode.CHECK_REGISTER_TIME;

/**
 * (ActivityBasics)表服务实现类
 *
 * @author 王伟成
 * @since 2023-09-12 16:33:45
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ActivityBasicsServiceImpl implements ActivityBasicsService {

    private final ActivityBasicsDao activityBasicsDao;

    private final ActivityAwardService activityAwardService;

    private final UserEquityPropsService userEquityPropsService;

    private final EquityPropsDao equityPropsDao;

    private final UserPrizeDrawRecordsDao userPrizeDrawRecordsDao;

    private final PrizeDrawActivityPoolDao prizeDrawActivityPoolDao;

    private final PrizeDrawActivityRewardsDao prizeDrawActivityRewardsDao;

    private final CarveUpPoolService carveUpPoolService;

    private final ActivityTaskRelationService activityTaskRelationService;

    private final ActivityTaskDao activityTaskDao;

    private final ActivityTaskPrizeDao activityTaskPrizeDao;

    private final HistoryPrizeDrawActivityDetailsLogDao historyPrizeDrawActivityDetailsLogDao;

    private final UserEquityPropsDao userEquityPropsDao;

    private final PrizeDrawActivitySettleRecordsDao prizeDrawActivitySettleRecordsDao;

    private final RewardAllocationService rewardAllocationService;

    private final SupplementarySignatureFrequencyService supplementarySignatureFrequencyService;

    private final SignInCollectionDao signInCollectionDao;

    private final UserSignInDao userSignInDao;

    private final UserRewardDao userRewardDao;

    private final UserCollectionService userCollectionService;

    private final RedisTemplate redisTemplate;

    private final UserAssetsService userAssetsService;
    private final UserSignInService userSignInService;

    private final DigitalCollectionService digitalCollectionService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long save(ActivityBasicsSaveDTO activityBasicsSaveDTO) {
//        if (activityBasicsSaveDTO.getStartTime().before(new Date())) {
//            throw new GlobalRunTimeException("上架时活动开始时间必须大于当前");
//        }
        ActivityBasics activityBasics = BeanUtil.copyProperties(activityBasicsSaveDTO, ActivityBasics.class);

        if(ObjectUtil.isNotNull(activityBasicsSaveDTO.getType())){
            activityBasics.setType(PrizeDrawActivityTypeEnum.getByCode(activityBasicsSaveDTO.getType()));
        }
        activityBasics.setStatus(0);
        Date nextDay23PM = DateUtil.offset(activityBasics.getEndTime(), DateField.HOUR_OF_DAY, 24); // 偏移到第二天
        nextDay23PM.setHours(23);
        nextDay23PM.setSeconds(0);
        nextDay23PM.setMinutes(0);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String formattedDate = dateFormat.format(nextDay23PM);
        activityBasics.setLotteryTime(nextDay23PM);
        activityBasics.setLotteryTimeVar(formattedDate);
        activityBasics.insert();
        return activityBasics.getId();
    }

    @Override
    public List<ActivityBasicsListVO> activityBasicsList() {
        //读取当前所上架的活动列表
        return activityBasicsDao.activityBasicsList();
    }

    @Override
    public ParticipationDateDataVO dayStatisticalData(Long activityBasicsId) {
        ActivityBasics activityBasics = activityBasicsDao.getById(activityBasicsId);
        Assert.isFalse(ObjectUtil.isNull(activityBasics),()->new GlobalRunTimeException("签到活动不存在"));
        ParticipationDateDataVO participationDateDataVO = new ParticipationDateDataVO();
        //获取日参与统计数据
        participationDateDataVO.setDailyParticipationStatistics(userSignInDao.dayStatisticalData(activityBasicsId,activityBasics.getStartTime()));
        return participationDateDataVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean userSignIn(Long id,UserInfo user) {

        //获取活动基础数据
        ActivityBasics activityBasics = activityBasicsDao.getById(id);

        //3：获取签到偏移量 value : signInOffset = 今天是这个月的第几天 - 1
        Date date = new Date();
        int signInOffset = DateUtil.dayOfMonth(date);
        String signInKey = RedisKeyEnum.USER_SIGN_IN.getKey() + activityBasics.getId() + user.getId() + DateUtil.format(date, "yyyy-MM");

        Boolean signInKeyIsExist = redisTemplate.hasKey(signInKey);

        //判断该用户的 覆盖
        if(!signInKeyIsExist){
            //需要覆盖的签到数据
            List<UserSignIn> userSignInList = userSignInService.getSignInTimeByActivityBasicsIdAndUserId(id,user.getId());

            //活动上架 根据活动Id获取这个活动中所有用户的签到signInTime
            if(ObjectUtil.isNotEmpty(userSignInList)){
                //如果存在签到的用户，按照指定key规则拼接key 并且组装offset
                userSignInList.forEach(userSignIn -> {
                    String signInKeyPre = DateUtil.format(userSignIn.getSignInTime(), "yyyy-MM");
                    String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),userSignIn.getUserId(),signInKeyPre);
                    redisTemplate.opsForValue().setBit(userSignInKey,DateUtil.dayOfMonth(userSignIn.getSignInTime()),Boolean.TRUE);
                });
            }
        }

        //1：进行持有藏品、注册时间校验；
        activitySignInCheck(user,activityBasics);

        //2：获取签到活动奖励配置周期
        List<RewardAllocation> rewardByActivitys = rewardAllocationService.getRewardByActivityId(activityBasics.getId());

        //4：获取redis签到 key = 签到key + 签到活动Id + 用户Id + 年 月
        String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),DateUtil.format(date, "yyyy-MM"));
        Boolean userIsAlreadySignIn = redisTemplate.opsForValue().getBit(userSignInKey,signInOffset);
        //5进行签到 已经签到则返回
        if(userIsAlreadySignIn){
            return Boolean.TRUE;
        }else {
            //先查数据库
            if(userSignInDao.getIsSignInByUserId(user.getId(),activityBasics.getId()) == 1){
                redisTemplate.opsForValue().setBit(userSignInKey,signInOffset,Boolean.TRUE);
                return Boolean.TRUE;
            }
            redisTemplate.opsForValue().setBit(userSignInKey,signInOffset,Boolean.TRUE);
        }

        //签到数据落库
        UserSignIn userSignIn = new UserSignIn();
        userSignIn.setUserId(user.getId());
        userSignIn.setSignInTime(date);
        userSignIn.setActivityBasicsId(activityBasics.getId());
        userSignIn.setSignInSource(SingInSourceEnum.NORMAL_SIGN_IN_SOURCE);
        userSignIn.insert();

        //6.1获取用户从活动开始签到了几个月
        int userSignInMonth = getUserSignInMonth(activityBasics, date);

        //6.2统计活动时间到今天用户所有的签到数据
        List<Integer> signInMonthTotal = getUserSignInTotalDay(activityBasics,user,userSignInMonth);

        //如果是连续签到判断当前连续签到天数落在哪一个区间
        Integer nowSignInDay = getSignCountTotal(signInMonthTotal,activityBasics.getType());

        //6.3按照活动类型的不同奖励周期配置 计算应发放奖励
        rewardByActivitys.forEach(rewardAllocation -> {
            //6.3.1奖励配置周期
            Integer signInDay = rewardAllocation.getSignInDay();

            //6.3.2连续签到活动
            if(rewardAllocation.getSignInType().getCode() == PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() && signInDay.intValue() == nowSignInDay){
                Integer userRewardReceiveRecord = userRewardDao.getUserRewardByRewardAllocationId(rewardAllocation.getId(),user.getId());
                if(userRewardReceiveRecord < rewardAllocation.getReceiveLimit()){
                    log.info("开始发放奖励{}");
                    sendPrize(user,rewardAllocation.getId(),activityBasics);
                }
                //6.3.3判断用户在所有的签到时间内，连续签到次数满足奖励周期配置的天数有多少次，是否还需发放奖励
//                Integer signCount = getSignCount(signInMonthTotal,signInDay,rewardAllocation,PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY,user,Boolean.FALSE);
//                if(ObjectUtil.isNotNull(signCount)){
//                    //6.3.3.1对该档位发放一次对应的奖励
//                    sendPrize(user,rewardAllocation.getId(),activityBasics);
//                }
            }

            //6.3.3累计签到活动
            if(rewardAllocation.getSignInType().getCode() == PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY.getCode()){
                Integer supplementarySignatureCount = userSignInService.getSupplementarySignatureCount(user.getId(),activityBasics.getId());
                int cumulativeSignInDay = getSignCountTotal(signInMonthTotal,activityBasics.getType()) + supplementarySignatureCount;

                if(signInDay.intValue() == cumulativeSignInDay){
                    sendPrize(user,rewardAllocation.getId(),activityBasics);
                }
                //计算所有用户签到的天数 firstSignInMonth
//                Integer signCount = getSignCount(signInMonthTotal, signInDay, rewardAllocation,PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY,user,Boolean.FALSE);
//                if(ObjectUtil.isNotNull(signCount)){
//                    //6.3.1对该档位发放一次对应的奖励
//                    sendPrize(user,rewardAllocation.getId(),activityBasics);
//                }
            }
        });

        return userIsAlreadySignIn;
    }


    /**
     * 测试签到接口
     * @param id
     * @param signInDate
     * @param signInDays
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean userSignIn(Long id, String signInDate, Integer signInDays, UserInfo user){
        //先判断是否需要恢复数据


        //获取活动基础数据
        ActivityBasics activityBasics = activityBasicsDao.getById(id);

        //1：进行持有藏品、注册时间校验；
        activitySignInCheck(user,activityBasics);

        //2：获取签到活动奖励配置周期
        List<RewardAllocation> rewardByActivitys = rewardAllocationService.getRewardByActivityId(activityBasics.getId());

        //3：获取签到偏移量 value : signInOffset = 今天是这个月的第几天 - 1
//        Date date = new Date();
//        int signInOffset = DateUtil.dayOfMonth(date);
//        String signInKey = DateUtil.format(date, "yyyy-MM");

        //4：获取redis签到 key = 签到key + 签到活动Id + 用户Id + 年 月
        String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),signInDate);
        Boolean userIsAlreadySignIn = redisTemplate.opsForValue().getBit(userSignInKey,signInDays);
        //5进行签到 已经签到则返回
        if(userIsAlreadySignIn){
            return Boolean.TRUE;
        }else {
            redisTemplate.opsForValue().setBit(userSignInKey,signInDays,Boolean.TRUE);
        }

        //签到数据落库
        UserSignIn userSignIn = new UserSignIn();
        userSignIn.setUserId(user.getId());
        userSignIn.setSignInTime(new Date());
        userSignIn.setActivityBasicsId(activityBasics.getId());
        userSignIn.setSignInSource(SingInSourceEnum.NORMAL_SIGN_IN_SOURCE);
        userSignIn.insert();

        //6.1获取用户从活动开始签到了几个月
        int userSignInMonth = getUserSignInMonth(activityBasics, new Date());

        //6.2统计活动时间到今天用户所有的签到数据
        List<Integer> signInMonthTotal = getUserSignInTotalDay(activityBasics,user,userSignInMonth);

        //如果是连续签到判断当前连续签到天数落在哪一个区间
        Integer nowSignInDay = getSignCountTotal(signInMonthTotal,activityBasics.getType(),Boolean.FALSE);


        //6.3按照活动类型的不同奖励周期配置 计算应发放奖励
        rewardByActivitys.forEach(rewardAllocation -> {
            //6.3.1奖励配置周期
            Integer signInDay = rewardAllocation.getSignInDay();

            //6.3.2连续签到活动
            if(rewardAllocation.getSignInType().getCode() == 3){
                Integer userRewardReceiveRecord = userRewardDao.getUserRewardByRewardAllocationId(rewardAllocation.getId(),user.getId());
                if(userRewardReceiveRecord < rewardAllocation.getReceiveLimit()){
                    Integer count = getSignCount(signInMonthTotal,rewardAllocation.getSignInDay(),rewardAllocation,PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY,user,Boolean.TRUE);
                    if(ObjectUtil.isNotNull(count)){
                        sendPrize(user,rewardAllocation.getId(),activityBasics);
                    }
                }
                //6.3.3判断用户在所有的签到时间内，连续签到次数满足奖励周期配置的天数有多少次，是否还需发放奖励
//                Integer signCount = getSignCount(signInMonthTotal,signInDay,rewardAllocation,PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY,user,Boolean.FALSE);
//                if(ObjectUtil.isNotNull(signCount)){
//                    //6.3.3.1对该档位发放一次对应的奖励
//                    sendPrize(user,rewardAllocation.getId(),activityBasics);
//                }
            }

            //6.3.3累计签到活动
            if(rewardAllocation.getSignInType().getCode() == 4 && signInDay.intValue() == nowSignInDay){
                Integer userRewardReceiveRecord = userRewardDao.getUserRewardByRewardAllocationId(rewardAllocation.getId(),user.getId());
                if(userRewardReceiveRecord.intValue() < 1){
                    sendPrize(user,rewardAllocation.getId(),activityBasics);
                }
                //计算所有用户签到的天数 firstSignInMonth
//                Integer signCount = getSignCount(signInMonthTotal, signInDay, rewardAllocation,PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY,user,Boolean.FALSE);
//                if(ObjectUtil.isNotNull(signCount)){
//                    //6.3.1对该档位发放一次对应的奖励
//                    sendPrize(user,rewardAllocation.getId(),activityBasics);
//                }
            }
        });

        return userIsAlreadySignIn;
    }

    //发放签到奖励
    private void sendPrize(UserInfo user, Long rewardAllocationId, ActivityBasics activityBasics){
        //获取一个奖励周期的内容 一个配置存在多个奖励
        List<ActivityAwardSaveDetailsVO> activityAwardSaveDetailsVOS = activityAwardService.getByRewardAllocationId(rewardAllocationId);

        if(ObjectUtil.isNotNull(activityAwardSaveDetailsVOS)){

            StringJoiner propName = new StringJoiner(" + ");
            activityAwardSaveDetailsVOS.forEach(activityAwardSaveDetailsVO -> {
                EquityProps equityProps = equityPropsDao.getById(activityAwardSaveDetailsVO.getPropId());
                switch (activityAwardSaveDetailsVO.getPropType()){
                    case 1:
                        //添加积分
                        userAssetsService.addIntegralByUserId(BigDecimal.valueOf(activityAwardSaveDetailsVO.getPropNum()),
                                user.getId(),CoinCategoryEnum.INTEGRAL,AssetChangeLogEnum.SIGN_IN_ACTIVITY,activityBasics.getId(),activityBasics.getNameActivity());
                        propName.add("星球碎片");
                        //添加日志记录用户签到发放奖励
//                        sendSignInPrizeLog(user.getId(),0L,activityBasics.getId(),rewardAllocationId,activityAwardSaveDetailsVO.getPropNum());
                        break;
                    case 2:
                        //添加权益道具
                        if(ObjectUtil.isNotNull(equityProps)){
                            userEquityPropsService.addEquityPropsByUser(equityProps,user.getId(), UserEquityPropsGetTypeEnum.SIGN_IN_ACTIVITY,activityAwardSaveDetailsVO.getPropNum(),
                                    activityBasics.getNameActivity(),activityBasics.getId(),BigDecimal.ZERO,UserEquityPropsGetTypeEnum.SIGN_IN_ACTIVITY,activityBasics.getId());
                            propName.add(equityProps.getFirstTitle());
                            //添加日志记录用户签到发放奖励
//                            sendSignInPrizeLog(user.getId(),equityProps.getId(),activityBasics.getId(),rewardAllocationId,activityAwardSaveDetailsVO.getPropNum());
                        }
                    default:
                }
            });

            //等待奖励发放完成然后添加记录
            RewardAllocation rewardAllocationById = rewardAllocationService.getRewardAllocationById(rewardAllocationId);
            sendSignInPrizeLog(user,propName.toString(),activityBasics.getId(),rewardAllocationId,rewardAllocationById.getSignInDay());
        }

    }


    private void sendSignInPrizeLog(UserInfo user,String propName,Long activityBasicsId,Long rewardAllocationId,Integer signInDay){
        UserReward userReward = new UserReward();
        userReward.setUserId(user.getId());
        userReward.setUserTel(user.getUserTel());
        userReward.setPropName(propName);
        userReward.setActivityBasicsId(activityBasicsId);
        userReward.setRewardAllocationId(rewardAllocationId);
        userReward.setSignInDay(signInDay);
        userReward.insert();
    }

    //获取用户从活动开始一直签到至今参与的签到记录
    private List<Integer> getUserSignInTotalDay(ActivityBasics activityBasics,UserInfo user,int userSignInMonth){

        ArrayList<Integer> signInMonthTotal = new ArrayList<>();
        //签到活动开始的月份
        int activityStartmonth = DateUtil.month(activityBasics.getStartTime()) + 1;
        //签到活动结束月份
        int activityEndmonth = DateUtil.month(activityBasics.getEndTime()) + 1;

        String signInKey = "";
        if(activityStartmonth < 10){
            signInKey = DateUtil.year(activityBasics.getStartTime()) + "-0" + activityStartmonth;
        }else {
            signInKey = DateUtil.year(activityBasics.getStartTime()) + "-" + activityStartmonth;
        }

        String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),signInKey);

        //用户一次活动所有的签到记录：获取第一个月有多少需要签到的天数 start
        //活动一个月签到结束的天数
        int activityStartMonthSignInDay = 0;
        //活动一个月签到开始的天数
        int activityStartDay = DateUtil.dayOfMonth(activityBasics.getStartTime());
        Date date = new Date();

        //说明活动只有一个月
        if(userSignInMonth == 0){
            //活动未结束 一个月签到的天数截至到今天
            if(activityBasics.getStartTime().before(date) &&
                    activityBasics.getEndTime().after(date)){
                activityStartMonthSignInDay = DateUtil.dayOfMonth(date);
            }else {
                //活动结束，获取活动结束天数
                activityStartMonthSignInDay = DateUtil.dayOfMonth(activityBasics.getEndTime());
            }
        }else {
            if(DateUtil.dayOfMonth(activityBasics.getStartTime()) == 1){
                activityStartMonthSignInDay = DateUtil.lengthOfMonth(DateUtil.month(activityBasics.getStartTime()) + 1,Boolean.TRUE);
                activityStartDay = 1;
            }else {
                //活动的那个开始时间不是月份的第一天，获取活动的开始天数是第几天
                activityStartDay = DateUtil.dayOfMonth(activityBasics.getStartTime());
                //一个月签到结束天数 = 活动的开始月的天数
                activityStartMonthSignInDay = DateUtil.lengthOfMonth(DateUtil.month(activityBasics.getStartTime()) + 1,Boolean.TRUE);
            }

        }

        //第一个月签到记录
        for (int i = activityStartDay; i <= activityStartMonthSignInDay; i++) {
            Boolean signInBit = redisTemplate.opsForValue().getBit(userSignInKey, i);
            if(Boolean.TRUE.equals(signInBit)){
                signInMonthTotal.add(1);
            }else {
                signInMonthTotal.add(0);
            }
        }

        //说明只有一个月并且在当月
        if(userSignInMonth == 0){
            return signInMonthTotal;
        }
        //end

        //获取活动开始至今 第二个月开始用户的所有的签到记录 考虑当月天数距今不满
        //活动结束月份
        for (int i = 1; i <= userSignInMonth; i++) {

            //签到月份
            int signInMonth = activityStartmonth + i;
            String signInContinuityKey = "";
            if(signInMonth < 10){
                signInContinuityKey = DateUtil.year(activityBasics.getStartTime()) + "-0" + signInMonth;
            }else {
                signInContinuityKey = DateUtil.year(activityBasics.getStartTime()) + "-" + signInMonth;
            }

            //签到key
            String userSignInContinuityKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),signInContinuityKey);

            //指定月的天数
            Integer lengthOfMonth = DateUtil.lengthOfMonth(activityStartmonth + i, Boolean.TRUE);

            //如果是当月
            if(signInMonth == activityEndmonth){
                //这个月就是活动结束月份:签到记录天数 = 用活动结束时间天数 或者 用当前时间天数
                if(activityBasics.getStartTime().before(date) &&
                        activityBasics.getEndTime().after(date)){
                    //活动未结束 当天的天数
                    lengthOfMonth = DateUtil.dayOfMonth(date);
                }else {
                    //活动已结束 活动结束的天数
                    lengthOfMonth = DateUtil.dayOfMonth(activityBasics.getEndTime());
                }
            }

            //获取每个月签到记录
            for (int j = 1; j <= lengthOfMonth ; j++) {
                Boolean signInBit = redisTemplate.opsForValue().getBit(userSignInContinuityKey, j);
                if(Boolean.TRUE.equals(signInBit)){
                    signInMonthTotal.add(1);
                }else {
                    signInMonthTotal.add(0);
                }
            }

            if(signInMonth == activityEndmonth){
                return signInMonthTotal;
            }
        }

        return signInMonthTotal;
    }

    //获取用户从活动开始签到了几个月
    private int getUserSignInMonth(ActivityBasics activityBasics ,Date date){

        //：获取活动时间，计算出距今有几个月 为了计算发放奖励 12 - 3 = 9   3 4 ... 12
        int activityMonth = DateUtil.month(activityBasics.getStartTime()) + 1;
        int nowMonth = DateUtil.month(date) + 1;
        int differenceDay = 0;
        if(activityMonth == nowMonth){
            //活动和当前时间在同一个月下
            return differenceDay;
        }else {
            //活动和当前时间相距几个月 1 = 5 - 4
            differenceDay = nowMonth - activityMonth;
        }
        return differenceDay;
    }

    /**
     * 如果是累计签到获取总签到天数 如果是连续签到获取第一次断签的天数
     * @param signInMonthTotal
     * @param type
     * @return
     */
    private Integer getSignCountTotal(List<Integer> signInMonthTotal,PrizeDrawActivityTypeEnum type){

        Integer userContinuityDay = 0;

        if (CollUtil.isNotEmpty(signInMonthTotal)) {

            for (int i = signInMonthTotal.size(); i > 0 ; i--) {

                //如果今天未签到，获取上一次连续签到最大天数，否则获取至今。
                if(i == signInMonthTotal.size() && signInMonthTotal.get(i - 1) == 0){
                    continue;
                }
                if(1 == signInMonthTotal.get(i - 1) ){
                    userContinuityDay = userContinuityDay + 1;
                }else {
                    if(PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() == type.getCode()){
                        return userContinuityDay;
                    }
                }
            }
        }

        return userContinuityDay;
    }

    private Integer getSignCountTotal(List<Integer> signInMonthTotal,PrizeDrawActivityTypeEnum type,Boolean isExist){

        Integer userContinuityDay = 0;

        if (CollUtil.isNotEmpty(signInMonthTotal)) {

            for (int i = signInMonthTotal.size(); i > 0 ; i--) {

                //如果今天未签到，获取上一次连续签到最大天数，否则获取至今。
//                if(i == signInMonthTotal.size() && signInMonthTotal.get(i - 1) == 0 || isExist){
//                    continue;
//                }
                if(1 == signInMonthTotal.get(i - 1) ){
                    userContinuityDay = userContinuityDay + 1;
                }else {
                    if(PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() == type.getCode()){
                        return userContinuityDay;
                    }
                }
            }
        }

        return userContinuityDay;
    }

    /**
     *
     * @param signInMonthTotal 签到活动距今所有的签到记录
     * @param signInDay 签到活动配置的奖励周期天数
     * @param rewardAllocation  签到奖励周期配置
     * @param type  签到活动类型
     * @param user  用户
     * @param firstContinuitySignIn  是否统计第一次最大连续签到天数
     * @return 签到奖励周期配置Id
     * @throws Exception
     */
    private Integer getSignCount(List<Integer> signInMonthTotal,Integer signInDay,RewardAllocation rewardAllocation,PrizeDrawActivityTypeEnum type,UserInfo user,Boolean firstContinuitySignIn) {

        //用户连续签到天数 累计签到天数//CONTINUITY
        Integer userContinuityDay = 0;

        //用户满足签到周期奖励配置多少次
        int userRewardCount = 0;

        Integer supplementaryCount = 0;

        if (CollUtil.isNotEmpty(signInMonthTotal)) {

            //统计用户签到次数和满足奖励周期天数
            for (int i = signInMonthTotal.size(); i > 0 ; i--) {
                //签到次数 +1
                if(1 == signInMonthTotal.get(i - 1)){
                    userContinuityDay = userContinuityDay + 1;

                    //累计签到的时候满足了多少奖励配置
                    if(userContinuityDay.equals(signInDay)){
                        userRewardCount = userRewardCount + 1 ;
                    }
                }else {
                    //需要补签的天数
                    supplementaryCount = supplementaryCount + 1;

                    //如果是连续签到需要清0
                    if(PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() == type.getCode()){
                        //连续签到天数满足奖励周期天数
                        if(userContinuityDay.equals(signInDay)){
                            userRewardCount = userRewardCount + 1 ;
                        }
                        userContinuityDay = 0;
                    }
                }
            }
        }

        //为了发放历史奖励
        if(userContinuityDay.equals(signInDay) && firstContinuitySignIn ){
            userRewardCount = 1;
        }

        //返回未签到天数
//        if(firstContinuitySignIn){
////            return supplementaryCount;
////        }

        //签到次数达到了奖励配置周期 累计的签到次数 = 签到次数 + 补签次数
        if (PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY.getCode() == type.getCode()){
            Integer supplementarySignatureCount = userSignInService.getSupplementarySignatureCount(user.getId(),rewardAllocation.getActivityBasicsId());
            userContinuityDay  = userContinuityDay + supplementarySignatureCount;
        }
        if(signInDay.intValue() == 0){
            return null;
        }

        if(userContinuityDay.equals(signInDay) || userRewardCount != 0){

            //根据rewardByActivityId获取用户已发放奖励次数
            Integer userRewardReceiveRecord = userRewardDao.getUserRewardByRewardAllocationId(rewardAllocation.getId(),user.getId());

            //根据rewardByActivityId获取签到奖励周期配置领取上限
            //连续签到才有奖励领取上限
            if(PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() == type.getCode()){
                if(firstContinuitySignIn){
                    if(userRewardReceiveRecord < userRewardCount && userRewardReceiveRecord < rewardAllocation.getReceiveLimit()){
                        //todo 为了发放历史奖励，上线需要注释的判断存在需要发放的奖励，
                        return 1;
                    }
                }
                if(userRewardReceiveRecord >= rewardAllocation.getReceiveLimit()){
                    //该签到档位奖励已达上限
                    return 1;
                }
                return null;
            }else {
                //是否还需要给用户发放奖励
                if(userRewardReceiveRecord.intValue() > 0){
                return null;
                 }
            }
            return userRewardCount;
        }else {
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userSupplementarySignIn(Long id, Integer supplementarySignatureCardDayNum,UserInfo user) {
        ActivityBasics activityBasics = activityBasicsDao.getById(id);

        //校验用户是否满足参与条件
        activitySignInCheck(user,activityBasics);

        //查询活动需要使用的补签卡道具 只有一个补签配置
        List<SupplementarySignatureVO> supplementarySignatureVOS = supplementarySignatureFrequencyService.getByActivityBasicsId(activityBasics.getId());
        Assert.isFalse(ObjectUtil.isEmpty(supplementarySignatureVOS),()->new GlobalRunTimeException("补签配置不存在"));
        Long supplementarySignaturePropId = supplementarySignatureVOS.get(0).getSupplementarySignaturePropId();

        //根据补签配置Id获取用户拥有多少个补签卡
        Integer myEquityCount = userEquityPropsDao.getMyEquityPropsByEquityPropsId(user.getId(),supplementarySignaturePropId);
        Assert.isFalse(ObjectUtil.isNull(myEquityCount) || myEquityCount <= 0 ,()->new GlobalRunTimeException("补签道具不足"));

        //道具卡补签消耗数量
        Integer supplementarySignaturePropNumber = supplementarySignatureVOS.get(0).getSupplementarySignaturePropNumber();

        //道具卡补签上限
        Integer supplementarySignaturePropCount = supplementarySignatureVOS.get(0).getSupplementarySignaturePropCount();
        Assert.isFalse(supplementarySignaturePropCount < supplementarySignatureCardDayNum,()->new GlobalRunTimeException("补签卡次数不足"));

        //一次补签消耗道具数量 = 补签消耗道具数量 < 用户拥有数量
        Integer consumeEquityCount = supplementarySignatureCardDayNum * supplementarySignaturePropNumber;
        Assert.isTrue(consumeEquityCount <= myEquityCount,()->new GlobalRunTimeException("补签道具不足"));

        //获取用户从活动开始签到了几个月
        Date date = new Date();
        int userSignInMonth = getUserSignInMonth(activityBasics, date);

        //统计活动时间到今天用户所有的签到数据
        List<Integer> signInMonthTotal = getUserSignInTotalDay(activityBasics,user,userSignInMonth);

        //这里获取的是用户签到天数
        Integer signInTotalOfMonth = getSignCountTotal(signInMonthTotal,PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY);

        //所有未签到天数 包括今天 = signInMonthTotal - signInTotalOfMonth

        //从补签记录中查询用户补签了多少次 0
        Integer supplementarySignatureCount = userSignInService.getSupplementarySignatureCount(user.getId(),activityBasics.getId());

        //signInTotalOfMonth.intValue()
        int noSupplementarySignatureDay = signInMonthTotal.size() - signInTotalOfMonth;
        //如果未签到天数和已经补签次数相同返回不存在可补签天数
        Assert.isFalse(noSupplementarySignatureDay == 0 && supplementarySignatureCount.intValue() == 0,()->new GlobalRunTimeException("当前无需补签！"));

        //补签不能补当前 判断用户今天是否签到
        String signInKey = DateUtil.format(date, "yyyy-MM");
        int signInOffset = DateUtil.dayOfMonth(date);
        String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),signInKey);

        Boolean userIsAlreadySignIn = redisTemplate.opsForValue().getBit(userSignInKey,signInOffset);
        if(!userIsAlreadySignIn){
            Assert.isFalse(Objects.equals(noSupplementarySignatureDay - 1,supplementarySignatureCount),()->new GlobalRunTimeException("当前无需补签！"));
        }else {
            Assert.isFalse(Objects.equals(noSupplementarySignatureDay,supplementarySignatureCount),()->new GlobalRunTimeException("当前无需补签！"));
        }

        //剩余的可签到上限 = 补签配置上限 - 用户补签了多少次
        int surplusSupplementarySignatureCount = supplementarySignaturePropCount - supplementarySignatureCount;
        Assert.isFalse(supplementarySignatureCardDayNum > surplusSupplementarySignatureCount,()->new GlobalRunTimeException("可补签次数不足！"));

        //获取奖励配置
        List<RewardAllocation> rewardByActivitys = rewardAllocationService.getRewardByActivityId(activityBasics.getId());

        Assert.isFalse(ObjectUtil.isEmpty(rewardByActivitys),()->new GlobalRunTimeException("累计签到活动奖励为空"));

        //累计签到天数 = 累计签到天数 + 补签天数
        Integer nowSignInDay = getSignCountTotal(signInMonthTotal,activityBasics.getType()) + supplementarySignatureCount;

        for (RewardAllocation rewardAllocation : rewardByActivitys){
            if(nowSignInDay.equals(rewardAllocation.getSignInDay())){
                //发放奖励
                sendPrize(user,rewardAllocation.getId(),activityBasics);
                break;
            }
        }

        //查询出指定的权益道具的类型
        List<UserEquityProps> havingListByUserIdAndEquityPropsIdAndLimit = userEquityPropsDao.getHavingListByUserIdAndEquityPropsIdAndLimit(supplementarySignaturePropId, user.getId(), 1);
        if(ObjectUtil.isNotNull(havingListByUserIdAndEquityPropsIdAndLimit) && havingListByUserIdAndEquityPropsIdAndLimit.size() > 0){
            //消耗道具 doSubVoucher
            userEquityPropsService.subVoucher(supplementarySignaturePropId,havingListByUserIdAndEquityPropsIdAndLimit.get(0).getTypeClassify(),user.getId(),consumeEquityCount,activityBasics.getNameActivity(),activityBasics.getId(),UserEquityPropsUseTypeEnum.SUPPLEMENTARY_SIGN_IN);

            //添加补签记录
            UserSignIn userSignIn = new UserSignIn();
            userSignIn.setUserId(user.getId());
            userSignIn.setSignInTime(new Date());
            userSignIn.setActivityBasicsId(activityBasics.getId());
            userSignIn.setSignInSource(SingInSourceEnum.SUPPLEMENTARY_SIGN_IN_SOURCE);
            userSignIn.insert();
        }
    }

    @Override
    public SignInActivityBasicsDetailsVO signInDetailsById(Long id, UserInfo user) {

        Date date = new Date();

        SignInActivityBasicsDetailsVO signInActivityBasicsDetailsVO = new SignInActivityBasicsDetailsVO();
        //获取签到活动配置
        ActivityBasics activityBasics = activityBasicsDao.getById(id);

        Assert.isFalse(ObjectUtil.isNull(activityBasics),()->new GlobalRunTimeException("活动不存在"));

        signInActivityBasicsDetailsVO.setActivitySignInTime(StrUtil.format("{} ~ {}",DateUtil.format(activityBasics.getStartTime(),"yyyy-MM-dd"),DateUtil.format(activityBasics.getEndTime(),"yyyy-MM-dd")));

        //是否配置了补签道具
        List<SupplementarySignatureVO> byActivityBasicsId = supplementarySignatureFrequencyService.getByActivityBasicsId(id);

        if(ObjectUtil.isEmpty(byActivityBasicsId)){
            signInActivityBasicsDetailsVO.setIsSupplementarySignature(Boolean.FALSE);
        }else {
            signInActivityBasicsDetailsVO.setIsSupplementarySignature(Boolean.TRUE);
        }

        //活动未开始和已结束
        if(activityBasics.getEndTime().before(date) || activityBasics.getStartTime().after(date) || PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() == activityBasics.getType().getCode()){
            signInActivityBasicsDetailsVO.setIsSupplementarySignature(Boolean.FALSE);
        }

        //签到活动周期配置
        List<RewardAllocation> rewardByActivityList = rewardAllocationService.getRewardByActivityId(activityBasics.getId());
        Assert.isFalse(ObjectUtil.isNull(rewardByActivityList),()->new GlobalRunTimeException("奖励周期不存在"));

        int userSignInMonth = getUserSignInMonth(activityBasics, date);

        //在活动时间内的所有签到记录
        List<Integer> signInMonthTotal = getUserSignInTotalDay(activityBasics,user,userSignInMonth);

        //如果是连续签到 昨天没有签到 nowSignInDay = 0;
        Integer nowSignInDay = 0;
        if(PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() == activityBasics.getType().getCode()){
            DateTime yesterday = DateUtil.yesterday();
            int signInOffset = DateUtil.dayOfMonth(yesterday);
            String signInKey = DateUtil.format(yesterday, "yyyy-MM");

            String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),signInKey);
            Boolean yesterDayIsSignIn = redisTemplate.opsForValue().getBit(userSignInKey, signInOffset);
            if(yesterDayIsSignIn){
                //如果是累计签到获取总签到天数 如果是连续签到获取第一次断签的天数
                nowSignInDay = getSignCountTotal(signInMonthTotal,activityBasics.getType());
            }else {
                //如果今天签到了也算连续签到一天 date
                String userToDaySignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),DateUtil.format(date, "yyyy-MM"));
                Boolean toDayIsSignIn = redisTemplate.opsForValue().getBit(userToDaySignInKey, DateUtil.dayOfMonth(date));
                if(toDayIsSignIn){
                    nowSignInDay = 1;
                }
            }
        }else {
            nowSignInDay = getSignCountTotal(signInMonthTotal,activityBasics.getType());
        }

        //如果是累计签到获取总签到天数 如果是连续签到获取第一次断签的天数
//        nowSignInDay = getSignCountTotal(signInMonthTotal,activityBasics.getType());

        //如果是累计签到 nowSignInDay = nowSignInDay + 已经补签的次数
        if (PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY.getCode() == activityBasics.getType().getCode()) {
            //获取用户补签次数
            Integer supplementarySignatureCount = userSignInService.getSupplementarySignatureCount(user.getId(), activityBasics.getId());
            nowSignInDay = nowSignInDay + supplementarySignatureCount;
        }

        signInActivityBasicsDetailsVO.setActivitySignInDay(nowSignInDay);

        ArrayList<RewardAllocationVO> rewardAllocationVOS = new ArrayList<>();
        //把当前的签到信息添加
        RewardAllocationVO rewardAllocationFirstVO = new RewardAllocationVO();
        rewardAllocationFirstVO.setSignInDay(signInActivityBasicsDetailsVO.getActivitySignInDay());
        rewardAllocationFirstVO.setNowSignInDay(signInActivityBasicsDetailsVO.getActivitySignInDay());
        rewardAllocationFirstVO.setStatus(null);
        //累计签到需要加上可补签天数
        if(PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY.getCode() == activityBasics.getType().getCode()){
            if(ObjectUtil.isNotEmpty(byActivityBasicsId) && ObjectUtil.isNotNull(byActivityBasicsId.get(0))){
                //补签配置可以补签多少天
//                Integer supplementarySignaturePropCount = ObjectUtil.isEmpty(byActivityBasicsId) ? 0 : byActivityBasicsId.get(0).getSupplementarySignaturePropCount();
                //用户已经补签过多少天
                Integer supplementarySignatureCount = userSignInService.getSupplementarySignatureCount(user.getId(),activityBasics.getId());

                //判断今天是否签到
                int signInOffset = DateUtil.dayOfMonth(date);
                String signInKey = DateUtil.format(date, "yyyy-MM");

                //4：获取redis签到 key = 签到key + 签到活动Id + 用户Id + 年 月
                String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),signInKey);
                Boolean userIsAlreadySignIn = redisTemplate.opsForValue().getBit(userSignInKey,signInOffset);

                //所有需要补签的天数
                List<Integer> supplementaryDay = signInMonthTotal.stream().filter(integer -> integer.equals(0)).collect(Collectors.toList());

                //还剩下多少天未补签的  所有需要补签的包括今天 如果今天未签到 - 1 ；如果今天签到不需要 - 1
                Integer supplementary = supplementaryDay.size() - supplementarySignatureCount;
                if(supplementary < 0){
                    supplementary = 0;
                }//不管今天是否签到，都要排除掉今天的补签天数
                if(!userIsAlreadySignIn){
                    if((supplementary - 1) < 0 ) {
                        rewardAllocationFirstVO.setActivitySignInMessage("当前已" + activityBasics.getType().getDescription() + signInActivityBasicsDetailsVO.getActivitySignInDay() + "天");
                        rewardAllocationFirstVO.setSupplementaryDay(0);
                    }else {
                        rewardAllocationFirstVO.setSupplementaryDay(supplementary - 1);
                        rewardAllocationFirstVO.setActivitySignInMessage("当前已"+ activityBasics.getType().getDescription() + signInActivityBasicsDetailsVO.getActivitySignInDay() + "天" + ",可补签" + (supplementary - 1) + "天");
                    }
                }else {
                    rewardAllocationFirstVO.setSupplementaryDay(supplementary);
                    rewardAllocationFirstVO.setActivitySignInMessage("当前已"+ activityBasics.getType().getDescription() + signInActivityBasicsDetailsVO.getActivitySignInDay() + "天" + ",可补签" + supplementary + "天");
                }
            }else {
                rewardAllocationFirstVO.setActivitySignInMessage("当前已"+ activityBasics.getType().getDescription() + signInActivityBasicsDetailsVO.getActivitySignInDay() + "天");
                rewardAllocationFirstVO.setSupplementaryDay(0);
            }

        }else {
            rewardAllocationFirstVO.setActivitySignInMessage("当前已"+ activityBasics.getType().getDescription() + signInActivityBasicsDetailsVO.getActivitySignInDay() + "天");
        }
        rewardAllocationVOS.add(rewardAllocationFirstVO);

        Integer finalNowSignInDay = nowSignInDay;
        rewardByActivityList.forEach(rewardAllocation -> {

            RewardAllocationVO rewardAllocationVO = new RewardAllocationVO();
            rewardAllocationVO.setSignInDay(rewardAllocation.getSignInDay());
            rewardAllocationVO.setNowSignInDay(finalNowSignInDay);

            //获取奖励内容
            StringJoiner stringJoiner = new StringJoiner(",");
            List<ActivityAwardSaveDetailsVO> activityAwardSaveDetailsVOS = activityAwardService.getByRewardAllocationId(rewardAllocation.getId());
            activityAwardSaveDetailsVOS.forEach(activityAwardSaveDetailsVO -> {
                stringJoiner.add(StrUtil.format("{} * {}",activityAwardSaveDetailsVO.getPropName(),activityAwardSaveDetailsVO.getPropNum()));
            });

            if(rewardAllocation.getSignInType().getCode() == PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() ){
                //配置中不同周期的奖励信息
                String message = "连续签到" + rewardAllocation.getSignInDay() + "天，奖励" + stringJoiner;
                rewardAllocationVO.setActivitySignInMessage(message);
                if(rewardAllocation.getSignInDay() <= finalNowSignInDay){
                    rewardAllocationVO.setStatus(Boolean.TRUE);
                }else {
                    rewardAllocationVO.setStatus(Boolean.FALSE);
                }
                //如果领完了该档位的所有奖励，该状态恒为True
                Integer count = getSignCount(signInMonthTotal,rewardAllocation.getSignInDay(),rewardAllocation,PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY,user,Boolean.FALSE);
                if(ObjectUtil.isNotNull(count) && count.intValue() == 1){
                    rewardAllocationVO.setStatus(Boolean.TRUE);
                }
            }else {
                //配置中不同周期的奖励信息
                String message = "累计签到" + rewardAllocation.getSignInDay() + "天，奖励" + stringJoiner;
                rewardAllocationVO.setActivitySignInMessage(message);
                //如果当前配置天数小于已经签到天数
                if(rewardAllocation.getSignInDay() <= finalNowSignInDay){
                    rewardAllocationVO.setStatus(Boolean.TRUE);
                }else {
                    rewardAllocationVO.setStatus(Boolean.FALSE);
                }
            }
            rewardAllocationVO.setType(rewardAllocation.getSignInType().getCode());
            rewardAllocationVO.setSignInDay(rewardAllocation.getSignInDay());

            StringJoiner propName = new StringJoiner(",");
            StringJoiner reward = new StringJoiner(",");
            activityAwardSaveDetailsVOS.forEach(activityAwardSaveDetailsVO -> {
                propName.add(StrUtil.format("{} * {}",activityAwardSaveDetailsVO.getPropName(),activityAwardSaveDetailsVO.getPropNum()));
                reward.add(StrUtil.format("{}",activityAwardSaveDetailsVO.getPropName()));
            });

            rewardAllocationVO.setPropName(propName.toString());
            rewardAllocationVO.setRewardName(reward.toString());
            rewardAllocationVOS.add(rewardAllocationVO);

        });

        //签到状态
        String signInKey = DateUtil.format(date, "yyyy-MM");
        int signInOffset = DateUtil.dayOfMonth(date);
        String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId(),user.getId(),signInKey);

        Boolean userIsAlreadySignIn = redisTemplate.opsForValue().getBit(userSignInKey,signInOffset);

        //再活动时间内
        if(activityBasics.getStartTime().before(date) && activityBasics.getEndTime().after(date)){
            if(!userIsAlreadySignIn){
                signInActivityBasicsDetailsVO.setActivitySignInStatus(ActivitySignInStatusEnum.SIGN_IN);
            }else {
                signInActivityBasicsDetailsVO.setActivitySignInStatus(ActivitySignInStatusEnum.SIGN_IN_ALREADY);
            }
        }else {
            //活动未开始
            if(activityBasics.getStartTime().after(date)){
                signInActivityBasicsDetailsVO.setActivitySignInStatus(ActivitySignInStatusEnum.ACTIVITY_SIGN_IN_NOT_START);
            }
            if(activityBasics.getEndTime().before(date)){
                signInActivityBasicsDetailsVO.setActivitySignInStatus(ActivitySignInStatusEnum.ACTIVITY_SIGN_IN_END);
            }
        }

        //一天都没有签到，或者当天断签了
        if(signInActivityBasicsDetailsVO.getActivitySignInDay().equals(0)){
            signInActivityBasicsDetailsVO.setActivitySignInMessage("再" + activityBasics.getType().getDescription() + rewardAllocationVOS.get(0).getSignInDay() + "天，即可领取" + rewardAllocationVOS.get(0).getRewardName());
        }

        //去掉第一个
        List<RewardAllocationVO> rewardAllocationVOList = rewardAllocationVOS.subList(1, rewardAllocationVOS.size());

        //下一个档位的奖励
        List<RewardAllocationVO> rewardAllocationVOStatusOfFalse = rewardAllocationVOList.stream().filter(rewardAllocationVO -> !rewardAllocationVO.getStatus()).collect(Collectors.toList());
        if(ObjectUtil.isNotEmpty(rewardAllocationVOStatusOfFalse)){
            //签到信息 存在问题：下一个奖励配置为三天
            signInActivityBasicsDetailsVO.setActivitySignInMessage("再" + activityBasics.getType().getDescription() + (rewardAllocationVOStatusOfFalse.get(0).getSignInDay() - signInActivityBasicsDetailsVO.getActivitySignInDay()) + "天，即可领取" + rewardAllocationVOStatusOfFalse.get(0).getRewardName());
        }else {
            //领取完所有奖励
            signInActivityBasicsDetailsVO.setActivitySignInMessage("");
        }

        //记录已经签到信息
        signInActivityBasicsDetailsVO.setActivitySignInAlreadyMessage("当前已" + activityBasics.getType().getDescription() + signInActivityBasicsDetailsVO.getActivitySignInDay() + "天");
        signInActivityBasicsDetailsVO.setCoverImg(activityBasics.getCoverImg());
        signInActivityBasicsDetailsVO.setRuleImg(activityBasics.getRuleImg());
        //用户补签卡拥有数量 获取补签配置
        if(PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY.getCode() == activityBasics.getType().getCode()){
            List<SupplementarySignatureVO> supplementarySignatureVOS = supplementarySignatureFrequencyService.getByActivityBasicsId(activityBasics.getId());
            if(ObjectUtil.isNotEmpty(supplementarySignatureVOS) &&
                    ObjectUtil.isNotEmpty(byActivityBasicsId) && ObjectUtil.isNotNull(byActivityBasicsId.get(0))){
                Long supplementarySignaturePropId = supplementarySignatureVOS.get(0).getSupplementarySignaturePropId();

                Integer myEquityCount = userEquityPropsDao.getMyEquityPropsByEquityPropsId(user.getId(),supplementarySignaturePropId);
                signInActivityBasicsDetailsVO.setSupplementaryNum(myEquityCount);
                signInActivityBasicsDetailsVO.setSupplementaryName(supplementarySignatureVOS.get(0).getSupplementarySignaturePropName());

                //配置可补签上限
                Integer supplementarySignaturePropCount = supplementarySignatureVOS.get(0).getSupplementarySignaturePropCount();

                //用户已经补签了多少次
                Integer supplementarySignatureCount = userSignInService.getSupplementarySignatureCount(user.getId(),activityBasics.getId());

                int surplusSupplementarySignatureCount = supplementarySignaturePropCount - supplementarySignatureCount;
                signInActivityBasicsDetailsVO.setSupplementaryDay(surplusSupplementarySignatureCount);
            }else {
                signInActivityBasicsDetailsVO.setSupplementaryNum(0);
                signInActivityBasicsDetailsVO.setSupplementaryName("");
                signInActivityBasicsDetailsVO.setSupplementaryDay(0);
            }
        }

        signInActivityBasicsDetailsVO.setRewardAllocationVOS(rewardAllocationVOS);
        return signInActivityBasicsDetailsVO;
    }


    private void activitySignInCheck(UserInfo user,ActivityBasics activityBasics){
        //校验注册时间

        String registerMessage = "本次活动仅注册时间在" + DateUtil.format(activityBasics.getRegisterBeginTime(),"yyyy-MM-dd HH:mm:ss") + "~" + DateUtil.format(activityBasics.getRegisterEndTime(),"yyyy-MM-dd HH:mm:ss") + "新用户参与";

        //用户注册时间不满足
        if(activityBasics.getIsRegisterTime()){
            Assert.isTrue(activityBasics.getRegisterBeginTime().before(user.getCreateTime()) &&
                    activityBasics.getRegisterEndTime().after(user.getCreateTime()) ,()->new GlobalRunTimeException(CHECK_REGISTER_TIME,registerMessage));
        }

        Assert.isFalse(ObjectUtil.isNull(activityBasics),()->new GlobalRunTimeException("活动不存在"));
        Assert.isTrue(activityBasics.getStartTime().before(activityBasics.getEndTime()),()->new GlobalRunTimeException("签到活动已结束"));
        //任意持有【】、【】、【】即可参与
        if(activityBasics.getIsRelease()){
            //获取签到活动需要持有藏品集合
            List<CorrelationCollectionDTO> correlationCollectionDTOS = signInCollectionDao.getByActivityBasicsId(activityBasics.getId());
            List<Long> holdCollectionIds = correlationCollectionDTOS.stream().map(CorrelationCollectionDTO::getCollectionId).collect(Collectors.toList());

            if(ObjectUtil.isNotEmpty(correlationCollectionDTOS)){
                //判断用户是否拥有指定藏品
                List<UserCollection> userCollectionIds = userCollectionService.getCollectionIdByUserId(user.getId(),holdCollectionIds);

                StringBuffer stringBuffer = new StringBuffer("任意持有");
                for (int i = 0; i <correlationCollectionDTOS.size() ; i++) {
                    if(i == 0){
                        stringBuffer.append("【" + correlationCollectionDTOS.get(0).getCollectionName() + "】");
                    }else {
                        stringBuffer.append("、【" + correlationCollectionDTOS.get(i).getCollectionName() + "】");
                    }
                }
                stringBuffer.append("即可参与");
                Assert.isFalse(ObjectUtil.isEmpty(userCollectionIds),()->new GlobalRunTimeException(CHECK_HOLD_COLLECTION,Convert.toStr(stringBuffer)));
            }
        }
    }


    @Override
    public void lottery(String lotteryDrawTime, Long id, String lotteryDrawResult) {
        // 根据条件lotteryDrawTime获取符合的数据进行修改.
        activityBasicsDao.lottery(lotteryDrawTime, id, lotteryDrawResult);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createActivity(CreateActivityDTO createActivityDTO) {
        // 核心基础活动部分
        ActivityBasicsDTO activityBasics = createActivityDTO.getActivityBasics();

        //当前时间在活动时间内
        Date date = new Date();
        int compare = DateUtil.compare(date, activityBasics.getStartTime());
        Assert.isTrue(compare < 0,()->new GlobalRunTimeException("活动配置开始时间小于当前时间"));

        Assert.isFalse(ObjectUtil.isNull(activityBasics),()->new GlobalRunTimeException("请填写活动数据"));


        // 奖励周期配置天数必须依次递增
        List<ActivityAwardSaveDTO> activityAwards = createActivityDTO.getActivityAwards();
        Assert.isTrue(ObjectUtil.isNotEmpty(activityAwards),()->new GlobalRunTimeException("奖励周期不能为空"));

        //时间校验
        Assert.isTrue(activityBasics.getStartTime().before(activityBasics.getEndTime()), () -> new GlobalRunTimeException("结束时间必须大于开始时间"));
        Assert.isFalse(ObjectUtil.isNull(activityAwards), () -> new GlobalRunTimeException("请配置奖励"));

        //连续签到活动和累计签到活动
        if(createActivityDTO.getActivityBasics().getType().getCode() == 3 ||createActivityDTO.getActivityBasics().getType().getCode() == 4){
            Integer previousNumber = 0;
            for (int i = 0; i < activityAwards.size(); i++) {
                Integer currentNumber = activityAwards.get(i).getSignInDay();
                Assert.isTrue(previousNumber < currentNumber,()->new GlobalRunTimeException("奖励1的天数必须＜奖励2的天数"));
                previousNumber = currentNumber;
            }
            //补签配置
            List<SupplementarySignatureDTO> supplementarySignature = createActivityDTO.getSupplementarySignature();
            //新增签到活动
            Long activityBasicsId = saveSignInActivity(activityBasics);

            //开启关联藏品配置
            if(activityBasics.getIsRelease()){
                //新增关联藏品
                List<Long> releaseCollections = activityBasics.getReleaseCollections();
                List<DigitalCollection> correlationCollectionDTOS = digitalCollectionService.getCollectionListById(releaseCollections);

                correlationCollectionDTOS.forEach(correlationCollectionDTO -> {
                    SignInCollection signInCollection = new SignInCollection();
                    signInCollection.setCollectionId(correlationCollectionDTO.getId());
                    signInCollection.setActivityBasicsId(activityBasicsId);
                    Assert.isTrue(signInCollection.insert(),()->new GlobalRunTimeException("新增失败！"));
                });
            }

            //新增奖励配置
            rewardAllocationService.save(activityAwards,activityBasicsId,activityBasics.getType());

            //新增补签配置
            if(ObjectUtil.isNotEmpty(supplementarySignature) && ObjectUtil.isNotNull(supplementarySignature.get(0).getSupplementarySignaturePropId())){
                supplementarySignatureFrequencyService.save(supplementarySignature,activityBasicsId);
            }
        }else {
            // 核心部分新增
            ActivityBasicsSaveDTO activityBasicsSaveDTO = BeanUtil.copyProperties(activityBasics, ActivityBasicsSaveDTO.class);
            if (ObjectUtil.isNotNull(activityBasics.getType())) {
                activityBasicsSaveDTO.setType(activityBasics.getType().getCode());
            }
            Long activityBasicsId = save(activityBasicsSaveDTO);

            // 奖励部分新增
            activityAwardService.save(activityAwards,activityBasicsId);
            //任务
            List<ActivityTaskDTO> activityTasks = createActivityDTO.getActivityTasks();
            activityTaskRelationService.save(activityTasks, activityBasicsId);
        }
    }

    private Long saveSignInActivity(ActivityBasicsDTO activityBasicsDTO){
        ActivityBasics activityBasics = BeanUtil.copyProperties(activityBasicsDTO, ActivityBasics.class);
        activityBasics.setStatus(0);
        activityBasics.insert();
        return activityBasics.getId();
    }
    @Override
    public Page<ActivityBasicsVO> activityBasics(ActivityBasicsPageDTO activityListDTO) {
        return activityBasicsDao.activityBasics(activityListDTO);
    }
    @Override
    public void deleteById(Long id) {
        ActivityBasics activityBasics = activityBasicsDao.getById(id);
        if (activityBasics.getStatus().equals(1)) {
            throw new GlobalRunTimeException("上架禁止删除");
        }
        if (activityBasics.getType() == PrizeDrawActivityTypeEnum.PARTITION_ACTIVITY) {
            //需要把初始奖金回归
            Assert.isTrue(carveUpPoolService.addAmountByActivityBasicsId(activityBasics.getId(), activityBasics.getInitPoolReserve()), () -> new GlobalRunTimeException("删除失败,请稍后重试"));
        }
        activityBasicsDao.removeById(id);
    }
    @Override
    public ActivityBasicsDetailsVO detailsById(Long id) {
        ActivityBasicsDetailsVO activityBasicsDetailsVO = new ActivityBasicsDetailsVO();
        ActivityBasics activityBasics = activityBasicsDao.getById(id);
        Assert.isFalse(ObjectUtil.isNull(activityBasics),()->new GlobalRunTimeException("活动不存在"));
        activityBasicsDetailsVO.setActivityBasics(BeanUtil.copyProperties(activityBasics, ActivityBasicsVO.class));
        List<ActivityAward> activityAwards = activityAwardService.getByActivityBasicsId(activityBasics.getId());

        //关联藏品信息
        List<CorrelationCollectionDTO> correlationCollectionDTOS = signInCollectionDao.getByActivityBasicsId(id);
        List<Long> collectionsId = correlationCollectionDTOS.stream().map(CorrelationCollectionDTO::getCollectionId).collect(Collectors.toList());
        activityBasicsDetailsVO.getActivityBasics().setReleaseCollections(collectionsId);

        //签到活动奖励配置、奖励、补签
        if(activityBasics.getType().getCode() == 3 || activityBasics.getType().getCode() == 4){
            //活动奖励配置
            List<RewardAllocation> rewardAllocations = rewardAllocationService.getRewardByActivityId(id);

            ArrayList<ActivityAwardVO> activityAwardVOS = new ArrayList<>();
            rewardAllocations.forEach(rewardAllocation -> {
                ActivityAwardVO activityAwardVO = new ActivityAwardVO();
                activityAwardVO.setSignInDay(rewardAllocation.getSignInDay());
                activityAwardVO.setReceiveLimit(rewardAllocation.getReceiveLimit());

                //放置奖励内容
                StringJoiner stringJoiner = new StringJoiner(",");
                List<ActivityAwardSaveDetailsVO> activityAwardSaveDetailsVOS = activityAwardService.getByRewardAllocationId(rewardAllocation.getId());
                activityAwardSaveDetailsVOS.forEach(activityAwardSaveDetailsVO -> {
                    stringJoiner.add(StrUtil.format("{} * {}",activityAwardSaveDetailsVO.getPropName(),activityAwardSaveDetailsVO.getPropNum()));
                });

                activityAwardVO.setActivityAwardSaveDetails(activityAwardSaveDetailsVOS);
                activityAwardVO.setPropName(stringJoiner.toString());

                activityAwardVOS.add(activityAwardVO);
            });
            activityBasicsDetailsVO.setActivityAwards(activityAwardVOS);

            //补签配置
            activityBasicsDetailsVO.setSupplementarySignature(supplementarySignatureFrequencyService.getByActivityBasicsId(id));

            return activityBasicsDetailsVO;
        }

        // 奖励分组,让后组装把内容组装起来之后封到一个集合中
        Map<Integer, List<ActivityAward>> awardGrouping = activityAwards.stream().collect(Collectors.groupingBy(ActivityAward::getAwardLv));
        List<ActivityAwardVO> activityAwardList = new ArrayList<>();
        // 拆解组合多个奖励.
        awardGrouping.forEach((key, value) -> {
            ActivityAwardVO activityAwardVO = new ActivityAwardVO();
            activityAwardVO.setAwardLv(key);
            activityAwardVO.setAwardLvName(value.get(0).getAwardLvName());
            StringJoiner stringJoiner = new StringJoiner(",");
            value.forEach(activityAward -> {
                stringJoiner.add(StrUtil.format("{} * {}", activityAward.getPropName(), activityAward.getPropNum()));
            });
            activityAwardVO.setPropName(stringJoiner.toString());
            activityAwardList.add(activityAwardVO);
        });
        // 奖励内容
        activityBasicsDetailsVO.setActivityAwards(activityAwardList);
        //任务
        List<ActivityTask> taskByActivityId = activityTaskDao.getTaskByActivityId(id);
        List<Long> taskIds = taskByActivityId.stream().map(ActivityTask::getId).collect(Collectors.toList());
        List<ActivityTaskPrize> activityTaskPrizes = activityTaskPrizeDao.getByTaskIds(taskIds);
        List<ActivityTaskVO> dataList = new ArrayList<>();
        taskByActivityId.forEach(activityTask -> {
            ActivityTaskVO activityTaskVO = new ActivityTaskVO();
            activityTaskVO.setTaskId(activityTask.getId());
            activityTaskVO.setTaskName(activityTask.getTaskName());
            // 组装奖励
            StringJoiner stringJoiner = new StringJoiner(",");
            List<ActivityTaskPrize> collect = activityTaskPrizes.stream().filter(activityTaskPrize -> activityTaskPrize.getTaskId().equals(activityTask.getId())).collect(Collectors.toList());
            collect.forEach(activityTaskPrize -> {
                String format = StrUtil.format("{}*{}", activityTaskPrize.getType() == INTEGRAL ? INTEGRAL.getDescription() : activityTaskPrize.getEquityName(), activityTaskPrize.getPrize());
                stringJoiner.add(format);
            });
            activityTaskVO.setAward(stringJoiner.toString());
            dataList.add(activityTaskVO);
        });
        // 根据任务ID进行分组,分组后.进行每个组进行组合奖励内容
        activityBasicsDetailsVO.setActivityTasks(dataList);


        return activityBasicsDetailsVO;
    }
    @Override
    public void modificationActivity(ModificationActivityDTO modificationActivityDTO) {
        // 活动的基础属性只能修改个别部分.任务可以随意修改,所以任务必须先删除所有任务在重新进行关联
        ActivityBasics activityBasics = BeanUtil.copyProperties(modificationActivityDTO, ActivityBasics.class);
        // 修改内容时间等数据不允许更改,所以直接把修改的的内容进行更新就可以.
        activityBasicsDao.updateById(activityBasics);
        ActivityBasics basicsDaoById = activityBasicsDao.getById(modificationActivityDTO.getId());
        if(basicsDaoById.getType().getCode() == 1 || basicsDaoById.getType().getCode() == 2) {
            //删除所有任务
            activityTaskRelationService.deleteByActivityBasicsId(modificationActivityDTO.getId());

            //重新绑定任务.
            activityTaskRelationService.save(modificationActivityDTO.getActivityTasks(), modificationActivityDTO.getId());
        }

    }
    @Override
    public void unmount(Long id) {
        ActivityBasics activityBasics = activityBasicsDao.getById(id);
        if (activityBasics.getStatus().equals(0)) {
            // 目前为下架状态,更正为上架.验证是否满足上架条件
            if (activityBasics.getStartTime().before(new Date())) {
                throw new GlobalRunTimeException("上架时活动开始时间必须大于当前");
            }
            // 上架
            activityBasicsDao.unmount(id, Boolean.TRUE);
        }
        if (activityBasics.getStatus().equals(1)) {
            // 下架
            activityBasicsDao.unmount(id, Boolean.FALSE);
            //活动下架遍历所有的keys 清除缓存
            if(PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode() == activityBasics.getType().getCode() ||
                    PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY.getCode() == activityBasics.getType().getCode()){
                String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),activityBasics.getId());
                String pattern = userSignInKey + "*";
                Set activitySignInKeys = redisTemplate.keys(pattern);
                redisTemplate.delete(activitySignInKeys);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addCarveUpActivity(ActivityBasics activityBasics, PrizeDrawActivityPoolBonusTaypEnum bonusType, List<PrizeDrawActivityRewards> rewardList, List<ActivityTaskDTO> activityTasks) {
        //周期内只能创建一个任务
        Assert.isFalse(activityBasicsDao.getBooleanByIntraCycle(activityBasics.getStartTime(), activityBasics.getEndTime(), PrizeDrawActivityTypeEnum.PARTITION_ACTIVITY), () -> new GlobalRunTimeException("周期内只能有1个任务"));

        DateTime dateTime = DateUtil.offsetDay(activityBasics.getEndTime(), 1);
        dateTime.setHours(23);
        dateTime.setMinutes(0);
        dateTime.setSeconds(0);
        activityBasics.setLotteryTime(dateTime);

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        activityBasics.setLotteryTimeVar(dateFormat.format(dateTime));
        activityBasics.insert();

        String residualPrizePool = carveUpPoolService.getResidualPrizePool();
        Assert.isFalse(activityBasics.getInitPoolReserve().compareTo(Convert.toBigDecimal(residualPrizePool)) == 1, () -> new GlobalRunTimeException("奖池剩余奖金不足"));
        Assert.isTrue(carveUpPoolService.subAmountByActivityBasicsId(activityBasics.getId(), activityBasics.getInitPoolReserve()), () -> new GlobalRunTimeException("创建失败,请稍后重试"));


        //奖金池配置 赋值
        PrizeDrawActivityPool prizeDrawActivityPool = new PrizeDrawActivityPool();
        prizeDrawActivityPool.setBonusType(bonusType);
        prizeDrawActivityPool.setAmount(BigDecimal.ZERO);
        prizeDrawActivityPool.setActivityId(activityBasics.getId());
        prizeDrawActivityPool.setLinkScale(BigDecimal.ONE);
        prizeDrawActivityPool.insert();

        BigDecimal sum = BigDecimal.ZERO;
        //奖励配置配置
        for (PrizeDrawActivityRewards prizeDrawActivityRewards : rewardList) {
            prizeDrawActivityRewards.setActivityId(activityBasics.getId());
            //落库为小数
            prizeDrawActivityRewards.setScale(prizeDrawActivityRewards.getScale().movePointLeft(2));
            sum = sum.add(prizeDrawActivityRewards.getScale());
        }
        Assert.isTrue(sum.compareTo(BigDecimal.ONE) == 0, () -> new GlobalRunTimeException("中奖比例累加只能等于100%"));
        prizeDrawActivityRewardsDao.saveBatch(rewardList);
        //关联id
        activityTaskRelationService.save(activityTasks, activityBasics.getId());
    }

    @Override
    public AdminCarveUpActivityDetailsVO carveUpActivityDetailsById(Long activityId) {
        ActivityBasics activityBasics = activityBasicsDao.getById(activityId);
        Assert.notNull(activityBasics, () -> new GlobalRunTimeException("活动不存在"));
        Assert.isTrue(activityBasics.getType() == PrizeDrawActivityTypeEnum.PARTITION_ACTIVITY, () -> new GlobalRunTimeException("类型不正常"));
        AdminCarveUpActivityDetailsVO adminCarveUpActivityDetailsVO = BeanUtil.copyProperties(activityBasics, AdminCarveUpActivityDetailsVO.class);

        List<PrizeDrawActivityRewards> rewardList = prizeDrawActivityRewardsDao.getListByActivityId(activityId);
        List<AdminPrizeDrawActivityRewardsDetailsVO> rewardsDetailsVOList = BeanUtil.copyToList(rewardList, AdminPrizeDrawActivityRewardsDetailsVO.class);


        List<PrizeDrawActivityPool> pooList = prizeDrawActivityPoolDao.getListByActivityId(activityId);
        List<AdminPrizeDrawCctivityPoolDetailsVO> poolDetailsVOList = BeanUtil.copyToList(pooList, AdminPrizeDrawCctivityPoolDetailsVO.class);


        adminCarveUpActivityDetailsVO.setPoolDetailsVOList(poolDetailsVOList);
        adminCarveUpActivityDetailsVO.setRewardsDetailsVOList(rewardsDetailsVOList);

        List<ActivityTask> taskByActivityId = activityTaskDao.getTaskByActivityId(activityId);
        List<Long> taskIds = taskByActivityId.stream().map(ActivityTask::getId).collect(Collectors.toList());
        List<ActivityTaskPrize> activityTaskPrizes = activityTaskPrizeDao.getByTaskIds(taskIds);
        List<ActivityTaskVO> dataList = new ArrayList<>();
        taskByActivityId.forEach(activityTask -> {
            ActivityTaskVO activityTaskVO = new ActivityTaskVO();
            activityTaskVO.setTaskId(activityTask.getId());
            activityTaskVO.setTaskName(activityTask.getTaskName());
            // 组装奖励
            StringJoiner stringJoiner = new StringJoiner(",");
            List<ActivityTaskPrize> collect = activityTaskPrizes.stream().filter(activityTaskPrize -> activityTaskPrize.getTaskId().equals(activityTask.getId())).collect(Collectors.toList());
            collect.forEach(activityTaskPrize -> {
                String format = StrUtil.format("{}*{}", activityTaskPrize.getType() == INTEGRAL ? INTEGRAL.getDescription() : activityTaskPrize.getEquityName(), activityTaskPrize.getPrize());
                stringJoiner.add(format);
            });
            activityTaskVO.setAward(stringJoiner.toString());
            dataList.add(activityTaskVO);
        });
        // 根据任务ID进行分组,分组后.进行每个组进行组合奖励内容
        adminCarveUpActivityDetailsVO.setActivityTasks(dataList);

        return adminCarveUpActivityDetailsVO;
    }

    @Override
    public List<ActivityBasics> getLotteryDataByType(PrizeDrawActivityTypeEnum prizeDrawActivityTypeEnum) {
        return activityBasicsDao.getLotteryDataByType(prizeDrawActivityTypeEnum.getCode());
    }

    @Override
    public ParticipationDataVO getPageSecondaryMarketCollection(Long activityId) {
        ActivityBasics activityBasics = activityBasicsDao.getById(activityId);
        Assert.notNull(activityBasics, () -> new GlobalRunTimeException("活动不存在"));
        if (activityBasics.getIsSettle()) {
            return historyPrizeDrawActivityDetailsLogDao.getOneByActivityId(activityId);
        }

        ParticipationDataVO participationDataVO = new ParticipationDataVO();

        //区分签到活动和普通活动
        if(activityBasics.getType().getCode() == 3 || activityBasics.getType().getCode() == 4){
            //签到活动的 参与人数
            participationDataVO.setAttendUserCount(userSignInDao.getAttendUserCount(activityBasics.getId()));

            //参与次数
            participationDataVO.setAttendCount(userSignInDao.getAttendCount(activityBasics.getId()));

            //已发放奖励
            participationDataVO.setEquityCount(userRewardDao.equityCount(activityBasics.getId()));
            return participationDataVO;
        }

        Long l = userPrizeDrawRecordsDao.numberPeopleDrawn(activityBasics.getId());
        participationDataVO.setAttendUserCount(userPrizeDrawRecordsDao.numberPeopleDrawn(activityBasics.getId()));
        participationDataVO.setAttendCount(userPrizeDrawRecordsDao.numberDraws(activityBasics.getId()));
        participationDataVO.setEquityCount(userEquityPropsDao.lotteryTicketDistributionStatistics(activityBasics.getPropId(), activityBasics.getStartTime(), activityBasics.getEndTime(), null).longValue());
        participationDataVO.setUseEquityCount(userEquityPropsDao.lotteryTicketDistributionStatisticsEmploy(activityBasics.getPropId(), activityBasics.getStartTime(), activityBasics.getEndTime(), 1).longValue());

        if (activityBasics.getType() == PrizeDrawActivityTypeEnum.GUESSING_ACTIVITY) {
            return participationDataVO;
        }

        //本次活动累计金额
        BigDecimal accumulatedAmount = prizeDrawActivityPoolDao.getSumAmountByActivityId(activityBasics.getId());
        participationDataVO.setAccumulatedAmount(accumulatedAmount);

        //本次活动总金额
        BigDecimal add = activityBasics.getInitPoolReserve().add(accumulatedAmount);

        //本期当前预留金额
        BigDecimal reserveAmount = add.multiply(activityBasics.getPrizePoolReserve().movePointLeft(2));
        participationDataVO.setResidualAmount(reserveAmount);

        //总金额减去预留金额 = 本期发放金额
        participationDataVO.setDisbursementAmount(add.subtract(reserveAmount));
        //未结算的话 未发放金额等于0
        participationDataVO.setUnissuedAmount(BigDecimal.ZERO);
        //未结算的话 等于预留金额
        participationDataVO.setReserveAmount(reserveAmount);
        return participationDataVO;

    }

    @Override
    public IPage<LotteryDataPageVO> lotteryDataPage(Long activityId, String userTel, String lotteryDrawResultVar, String typeName, Page page) {
        ActivityBasics activityBasics = activityBasicsDao.getById(activityId);
        Assert.notNull(activityBasics, () -> new GlobalRunTimeException("活动不存在"));

        //连续签到活动和累计签到活动
        if(activityBasics.getType().getCode() == PrizeDrawActivityTypeEnum.CUMULATIVE_SIGN_IN_ACTIVITY.getCode() || activityBasics.getType().getCode() == PrizeDrawActivityTypeEnum.CONTINUITY_SIGN_IN_ACTIVITY.getCode()){
            //如果手机号未空，不返回数据
            if(StrUtil.isNotBlank(userTel)){
                return userSignInDao.getlotteryDataPage(activityBasics.getId(), page, userTel);
            }
        }

        if (activityBasics.getLotteryStatus() == 1) {//已开
            if (activityBasics.getType() == PrizeDrawActivityTypeEnum.PARTITION_ACTIVITY) { //瓜分活动
                return prizeDrawActivitySettleRecordsDao.carveUpLotteryDataPageByActivityId(page, activityId, userTel, lotteryDrawResultVar, typeName);
            }
            return prizeDrawActivitySettleRecordsDao.guessLotteryDataPageByActivityId(page, activityId, userTel, lotteryDrawResultVar, typeName);
        }
        return null;
    }

    @Override
    public void updateRewardsStatus(Long id, PrizeDrawActivitySettleStatisEnum status) {
        PrizeDrawActivitySettleRecords settleRecords = prizeDrawActivitySettleRecordsDao.getById(id);
        Assert.notNull(settleRecords, () -> new GlobalRunTimeException("记录不存在"));

        Assert.isFalse(settleRecords.getStatus() == PrizeDrawActivitySettleStatisEnum.ISSUED, () -> new GlobalRunTimeException("此奖励已发放,不能拦截"));
        Assert.isFalse(settleRecords.getIsSettle(), () -> new GlobalRunTimeException("此奖励已发放,不能拦截"));

        Assert.isTrue(prizeDrawActivitySettleRecordsDao.updateRewardsStatusById(id, status), () -> new GlobalRunTimeException("拦截失败,请稍后重试"));
    }

    @Override
    public ActivityBasics getById(Long activityId) {
        return activityBasicsDao.getById(activityId);
    }
    @Override
    public IPage<ActivityRecordVO> activityRecord(Page page) {
        return activityBasicsDao.activityRecord(page);
    }
    @Override
    public IPage<ActivationRecordVO> activationRecord(ActivationRecordDTO activationRecordDTO) {
        return activityBasicsDao.activationRecord(activationRecordDTO);
    }
    @Override
    public void sort(Long id, Integer sort) {
        activityBasicsDao.sort(id,sort);
    }

    @Override
    public void addPrizeDrawCctivityPool(List<PrizeDrawActivityPool> prizeDrawActivityPools) {
        for (PrizeDrawActivityPool prizeDrawActivityPool : prizeDrawActivityPools) {

            Assert.isTrue(NumberUtil.isGreaterOrEqual(Convert.toBigDecimal(100),prizeDrawActivityPool.getLinkScale()),()->new GlobalRunTimeException("比例不能超过100"));
            ActivityBasics activityBasics = activityBasicsDao.getById(prizeDrawActivityPool.getActivityId());
            Assert.isTrue(activityBasics.getStartTime().before(activityBasics.getEndTime()),()-> new GlobalRunTimeException("结束时间必须大于开始时间"));
            Integer count = prizeDrawActivityPoolDao.getCountByActivityIdAndBonusTypeAndLinkId(prizeDrawActivityPool.getActivityId(), prizeDrawActivityPool.getBonusType(), prizeDrawActivityPool.getLinkId());
            Assert.isTrue(count == 0,()-> new GlobalRunTimeException(StrUtil.format("{}已存在,请勿重复添加",prizeDrawActivityPool.getLinkName())));
            prizeDrawActivityPool.setLinkScale(prizeDrawActivityPool.getLinkScale().movePointLeft(2));
            prizeDrawActivityPool.insert();
        }
    }

    @Override
    public Page<ActivityBasics> page(Page page) {
        Page<ActivityBasics> activityBasicsPage = activityBasicsDao.webPage(page);
        return activityBasicsPage;
    }
    @Override
    public WebActivityBasicsDetailsVO webDetailsById(Long id, UserInfo user) {
        ActivityBasics activityBasics = activityBasicsDao.getById(id);
        if (BeanUtil.isEmpty(activityBasics)) {
            throw new GlobalRunTimeException("当前活动不存在");
        }
        if (activityBasics.getStatus().equals(0)) {
            throw new GlobalRunTimeException("当前活动不存在");
        }


        WebActivityBasicsDetailsVO webActivityBasicsDetailsVO = new WebActivityBasicsDetailsVO();
        Integer havingCountByUserId = userEquityPropsService.getHavingCountByUserId(activityBasics.getPropId(), user.getId());
        webActivityBasicsDetailsVO.setUserPropNum(havingCountByUserId);
        webActivityBasicsDetailsVO.setLotteryNum(userPrizeDrawRecordsDao.getUserActivitySum(id, user.getId()));
        webActivityBasicsDetailsVO.setLotteryTime(activityBasics.getLotteryTime());
        webActivityBasicsDetailsVO.setCurrentTime(DateUtil.date());
        if (activityBasics.getLotteryTime().before(new Date())) {
            webActivityBasicsDetailsVO.setLotteryDrawResult(activityBasics.getLotteryDrawResult());
        }
        webActivityBasicsDetailsVO.setPropName(activityBasics.getPropName());
        String accumulatedBonus = "0";
        if (activityBasics.getType() == PrizeDrawActivityTypeEnum.PARTITION_ACTIVITY) {
            BigDecimal sumAmountByActivityId = prizeDrawActivityPoolDao.getSumAmountByActivityId(id);
            accumulatedBonus = activityBasics.getInitPoolReserve().add(sumAmountByActivityId).setScale(0,BigDecimal.ROUND_DOWN).toPlainString();

        }

        webActivityBasicsDetailsVO.setStartTime(activityBasics.getStartTime());
        webActivityBasicsDetailsVO.setEndTime(activityBasics.getEndTime());
        webActivityBasicsDetailsVO.setNameActivity(activityBasics.getNameActivity());
        webActivityBasicsDetailsVO.setStartTimeStamp(activityBasics.getStartTime().getTime());
        webActivityBasicsDetailsVO.setEndTimeStamp(activityBasics.getEndTime().getTime());
        webActivityBasicsDetailsVO.setNowTimeStamp(DateTime.now().getTime());
        webActivityBasicsDetailsVO.setId(id);
        webActivityBasicsDetailsVO.setRuleImg(activityBasics.getRuleImg());
        webActivityBasicsDetailsVO.setType(activityBasics.getType());


        webActivityBasicsDetailsVO.setAccumulatedBonus(accumulatedBonus);
        return webActivityBasicsDetailsVO;
    }


    @Override
    public void testDate(){
        Date date = new Date();
        int signInOffset = DateUtil.dayOfMonth(date);
        String signInKey = DateUtil.format(date, "yyyy-MM");

        Boolean signInKeyIsExist = redisTemplate.hasKey(signInKey);

        Long id = 113L;
        Long userId = 4287442L;
        //判断该用户的 覆盖
        if(!signInKeyIsExist){
            //需要覆盖的签到数据
            List<UserSignIn> userSignInList = userSignInService.getSignInTimeByActivityBasicsIdAndUserId(id,userId);

            //活动上架 根据活动Id获取这个活动中所有用户的签到signInTime
            if(ObjectUtil.isNotEmpty(userSignInList)){
                //如果存在签到的用户，按照指定key规则拼接key 并且组装offset
                userSignInList.forEach(userSignIn -> {
                    String signInKeyPre = DateUtil.format(userSignIn.getSignInTime(), "yyyy-MM");
                    String userSignInKey = StrUtil.format("{}:{}:{}:{}",RedisKeyEnum.USER_SIGN_IN.getKey(),id,userSignIn.getUserId(),signInKeyPre);
                    redisTemplate.opsForValue().setBit(userSignInKey,DateUtil.dayOfMonth(userSignIn.getSignInTime()),Boolean.TRUE);
                });
            }
        }
    }

}
